
/*
 * @ProjectName: 编程学习
 * @Copyright:   2019 HangZhou Yi Dev, Ltd. All Right Reserved.
 * @address:     http://Yi.tech
 * @date:        2019/4/24 07:48
 * @email:       xiazhaoyang@live.com
 * @description: 本内容仅限于编程技术学习使用，转发请注明出处.
 */
package com.example.auth.service.impl;

import com.example.auth.common.constant.SecurityConstant;
import com.example.auth.dao.common.mapper.RoleRepository;
import com.example.auth.dao.common.mapper.UserAndRoleRepository;
import com.example.auth.dao.common.mapper.UserInfoRepository;
import com.example.auth.dao.common.model.Role;
import com.example.auth.dao.common.model.UserAndRole;
import com.example.auth.dao.common.model.UserInfo;
import com.example.auth.service.IUserDetailsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 *
 * </p>
 *
 * @author Yi
 * @version v1.0.0
 * @date 2019/4/24 07:48
 * @modificationHistory=========================逻辑或功能性重大变更记录
 * @modify By: {修改人} 2019/4/24`
 * @modify reason: {方法名}:{原因}
 * ...
 */
@Service("userDetailsService")
@Slf4j
public class UserDetailsServiceImpl implements IUserDetailsService {

    @Resource
    private UserInfoRepository userInfoRepository;

    @Resource
    private UserAndRoleRepository userAndRoleRepository;

    @Resource
    private RoleRepository roleRepository;

    @Resource
    private PasswordEncoder passwordEncoder;

    /**
     * Locates the user based on the username. In the actual implementation, the search
     * may possibly be case sensitive, or case insensitive depending on how the
     * implementation instance is configured. In this case, the <code>UserDetails</code>
     * object that comes back may have a username that is of a different case than what
     * was actually requested..
     *
     * @param username the username identifying the user whose data is required.
     * @return a fully populated user record (never <code>null</code>)
     * @throws UsernameNotFoundException if the user could not be found or the user has no
     *                                   GrantedAuthority
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserInfo userInfo = userInfoRepository.findByUserName(username);
        if (userInfo == null) {
            log.error(username + " not found");
            throw new UsernameNotFoundException(username + " not found");
        }
        final Map<Integer, String> roleIdNameMap = roleRepository.findAll().stream().collect(Collectors.toMap(Role::getRoleId, Role::getRoleName));
        List<SimpleGrantedAuthority> authorityList = userAndRoleRepository.findRoleListByUserId(userInfo.getUserId())
                .stream().map(p -> new SimpleGrantedAuthority(roleIdNameMap.get(p.getRoleId()))).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(authorityList.stream().filter(p -> SecurityConstant.ROLE_FORBIDDEN.equals(p.getAuthority())).collect(Collectors.toList()))) {
            log.error("黑名单用户，无法访问！");
            throw new AssertionError("黑名单用户，无法访问！");
        }
        return new User(userInfo.getUserName(), userInfo.getPassword(), authorityList);
    }

    /**
     * 注册
     *
     * @param userInfo
     */
    @Override
    public void register(UserInfo userInfo) {
        if (Objects.nonNull(userInfoRepository.findByUserName(userInfo.getUserName()))) {
            throw new AssertionError("用户已存在!");
        }
        //加密
        userInfo.setPassword(passwordEncoder.encode(userInfo.getPassword()));
        //添加用户
        UserInfo result = userInfoRepository.save(userInfo);
        List<Role> roles = roleRepository.findAll();
        Map<String, Integer> roleIdAndKeyMap = roles.stream().collect(Collectors.toMap(Role::getRoleName, Role::getRoleId));
        //根据名称绑定默认权限
        switch (userInfo.getUserName()) {
            case "u1":
                userAndRoleRepository.save(UserAndRole.builder().roleId(roleIdAndKeyMap.get(SecurityConstant.ROLE_ADMIN)).userId(result.getUserId()).build());
                break;
            case "u2":
                userAndRoleRepository.save(UserAndRole.builder().roleId(roleIdAndKeyMap.get(SecurityConstant.ROLE_USER)).userId(result.getUserId()).build());
                break;
            case "u3":
                userAndRoleRepository.save(UserAndRole.builder().roleId(roleIdAndKeyMap.get(SecurityConstant.ROLE_FORBIDDEN)).userId(result.getUserId()).build());
                break;
            case "trust":
                userAndRoleRepository.save(UserAndRole.builder().roleId(roleIdAndKeyMap.get(SecurityConstant.ROLE_USER)).userId(result.getUserId()).build());
                userAndRoleRepository.save(UserAndRole.builder().roleId(roleIdAndKeyMap.get(SecurityConstant.ROLE_ClIENT)).userId(result.getUserId()).build());
                userAndRoleRepository.save(UserAndRole.builder().roleId(roleIdAndKeyMap.get(SecurityConstant.ROLE_TRUST_ClIENT)).userId(result.getUserId()).build());
                break;
            default:
                userAndRoleRepository.save(UserAndRole.builder().roleId(roleIdAndKeyMap.get(SecurityConstant.ROLE_USER)).userId(result.getUserId()).build());
                userAndRoleRepository.save(UserAndRole.builder().roleId(roleIdAndKeyMap.get(SecurityConstant.ROLE_ClIENT)).userId(result.getUserId()).build());
                break;
        }

    }
}